/*Author: Andrew Shore
 * Class: CSCE 145 Section 004
 * Homework 9: Smiley Game
 * This program is a game similar to hangman where a unknown word is given and the user has to guess what it is.
 * 
 */
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class Smiley implements ActionListener {

		//class constants
	private final static String WORD_LIST="words.txt";
	private final static int OFFSET=2;
	private final static int TEXT_WIDTH=20;
	private final static int CANVAS_WIDTH=250;
	private final static int CANVAS_HEIGHT=150;
	private final static int WINDOW_WIDTH=300;
	private final static int WINDOW_HEIGHT=340;
	private final static Color SKY_BLUE=new Color(217,217,255);
	
	//Gui Instance Variables
	
	//window: frame for GUI
	private JFrame window=new JFrame(" :- Smiley");
	
	//answerLavel and answerPad: area for displaying mystery word
	private JLabel answerLabel=new JLabel(" Word");
	private JTextField answerPad=new JTextField(TEXT_WIDTH);
	
	//guessLabel and guessPad: entry area to make guess
	private JLabel guessLabel=new JLabel("Guess");
	private JTextField guessPad= new JTextField(TEXT_WIDTH);
	
	//updateButton: signaler that a new guess has been made
	private JButton updateButton=new JButton("Update");
	
	//facePad: drawing area for face
	private Canvas facePad=new Canvas();
	
	//pastLabel and pastPad: area for displaying past guesses
	private JLabel pastLabel=new JLabel("Past guesses");
	private JTextField pastPad=new JTextField(" ",TEXT_WIDTH);
	
	//resultPad: status area for game result
	private JLabel resultPad= new JLabel(" ");
	
	//game instance variables
	private String word;					//word to be guessed
	private StringBuffer answer;			//portion of word guessed so far
	private char guess;						//current letter guess
	private int errors;						//how many bad guesses so far
	private int lettersLeft;				//how many letters still needed
	private boolean gameOver;				//has the game been won or lost
	
	//default constructor
	public Smiley(){
		//picks random word from specified file
		word=getRandomWord();
		
		guess=' ';
		errors=0;
		lettersLeft=word.length();
		gameOver=false;
		
		String s=" ";
		for(int i=0; i<word.length(); ++i){
			s+=" _";
		}
		answer=new StringBuffer(s);
		
		//configure GUI
		window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.setBackground(SKY_BLUE);
		
		window.getContentPane().setBackground(window.getBackground());
		guessPad.setBackground(window.getBackground());
		answerPad.setBackground(window.getBackground());
		resultPad.setBackground(window.getBackground());
		pastPad.setBackground(window.getBackground());
		updateButton.setBackground(window.getBackground());
		
		answerPad.setText(answer.toString());
		
		updateButton.addActionListener(this);
		
		facePad.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
		facePad.setBackground(Color.WHITE);
		
		answerPad.setEditable(false);
		pastPad.setEditable(false);
		
		window.setLayout(new FlowLayout());
		
		window.add(answerLabel);
		window.add(answerPad);
		window.add(guessLabel);
		window.add(guessPad);
		window.add(updateButton);
		window.add(facePad);
		window.add(pastLabel);
		window.add(pastPad);
		window.add(resultPad);
		
		window.setVisible(true);
	}
	
	//Smile(): word-specified constructor
	public Smiley(String w){
		//process parameter
		if(w!=null){
			word=w;
		}
		else{
			word=getRandomWord();
		}
		
		//initialize state information
		
		//record number of letters still unfound
		lettersLeft=word.length();
		
		//current guess placeholder
		guess=' ';
		
		//no errant guesses as of yet
		errors=0;
		
		//the game is not over
		gameOver=false;
		
		//create mystery word representation, e.g., _ _ _ _
		String s=" ";
		for(int i=0; i<word.length(); ++i){
			s+=" _";
		}
		answer=new StringBuffer(s);
		
		//configure GUI
		window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.setBackground(SKY_BLUE);
		
		window.getContentPane().setBackground(window.getBackground());
		guessPad.setBackground(window.getBackground());
		answerPad.setBackground(window.getBackground());
		resultPad.setBackground(window.getBackground());
		pastPad.setBackground(window.getBackground());
		updateButton.setBackground(window.getBackground());
		
		answerPad.setText(answer.toString());
		
		updateButton.addActionListener(this);
		
		facePad.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
		facePad.setBackground(Color.WHITE);
		
		answerPad.setEditable(false);
		pastPad.setEditable(false);
		
		window.setLayout(new FlowLayout());
		
		window.add(answerLabel);
		window.add(answerPad);
		window.add(guessLabel);
		window.add(guessPad);
		window.add(updateButton);
		window.add(facePad);
		window.add(pastLabel);
		window.add(pastPad);
		window.add(resultPad);
		
		window.setVisible(true);
	}
	
	//isValid(): is current input guess valid
	private boolean isValid(String input){
		//input guess must be a single unseen letter
		if(input.length()!=1){
			//not a single character
			return false;
		}
		else if(!Character.isLetter(input.charAt(0))){
			//not a letter
			return false;
		}
		else{ //it's a letter -- is it previously unseen
			String past=pastPad.getText();
			input=input.toLowerCase();
			//indexOf() only returns -1 if the s is not there
			return(past.indexOf(input)==-1);
		}
	}
	
	//udpateAnswer(): see where current guess fits in word
	private void updateAnswer(){
		//assumer the character is not there
		boolean foundMatch=false;
		
		//go through the word character by character and look for matches with guess
		for(int i=0; i<word.length(); ++i){
			if(word.charAt(i)==guess){ //got a match
				foundMatch=true;
				--lettersLeft;
				answer.setCharAt(2*i+1, guess);
				answer.setCharAt(2*i+2, ' ');
				
			}
			
		}
		
		//update errors and gameOver as needed
		if(!foundMatch){
			++errors;
		}
		else if(lettersLeft==0){
			gameOver=true;
		}
		
		//update GUI
		answerPad.setText(answer.toString());
	}
	
	//drawContour(): draw the outline of the face
	private void drawContour(){
		int w=facePad.getWidth();
		int h=facePad.getHeight();
		int ow=w-2*OFFSET;
		int oh=h-2*OFFSET;
		Graphics g=facePad.getGraphics();
		g.setColor(window.getBackground());
		g.fillOval(OFFSET, OFFSET, ow, oh);
	}
	
	//drawLeftEye(): draw the left eye
	private void drawLeftEye(){
		int w=facePad.getWidth();
		int h=facePad.getHeight();
		int ow=w/8;
		int oh=h/8;
		Graphics g=facePad.getGraphics();
		g.setColor(Color.white);
		g.fillOval(OFFSET+w/4, OFFSET+h/4, ow, oh);
	}
	//drawRightEye(): draw the draw right eye
	private void drawRightEye(){
		int w=facePad.getWidth();
		int h=facePad.getHeight();
		int ow=w/8;
		int oh=h/8;
		Graphics g=facePad.getGraphics();
		g.setColor(Color.white);
		g.fillOval((OFFSET)+w/2 +ow, OFFSET+h/4 , ow , oh);
	}
	//drawNose(): draw the nose for our face
	private void drawNose(){
		int w=facePad.getWidth();
		int h=facePad.getHeight();
		int ow=w/8;
		int oh=h/8;
		Graphics g=facePad.getGraphics();
		g.setColor(Color.white);
		g.fillOval(OFFSET+w/2-ow/2, OFFSET+h/2, ow, oh);
		
	}
	//draws the right eyebrow for our face
	private void drawRightEyebrow(){
		int w=facePad.getWidth();
		int h=facePad.getHeight();
		int rw=w/8;
		int rh=2*OFFSET;
		Graphics g=facePad.getGraphics();
		g.setColor(Color.white);
		g.fillRect( OFFSET+w/2+w/8 ,OFFSET+h/4-rh , rw, rh);
		
	}
	//draws the left eyebrow for our face
	private void drawLeftEyebrow(){
		int w=facePad.getWidth();
		int h=facePad.getHeight();
		int rw=w/8;
		int rh=2*OFFSET;
		Graphics g=facePad.getGraphics();
		g.setColor(Color.white);
		g.fillRect( OFFSET+w/4 ,OFFSET+h/4-rh , rw, rh);
		
	}
	//draws the mouth for the smiley face
	private void drawMouth(){
		int w=facePad.getWidth();
		int h=facePad.getHeight();
		int rw=w/4;
		int rh=h/12;
		Graphics g=facePad.getGraphics();
		g.setColor(Color.white);
		g.fillRect(OFFSET+w/2-rw/2,OFFSET+h/2+rh+20   ,rw,rh);
	/*
		int w = facePad.getWidth();	
		int h = facePad.getHeight();	
		int ow = w / 8;	
		int oh = h / 8;	
		Graphics g = facePad.getGraphics();	
		g.setColor(Color.BLACK);	
		g.drawArc(OFFSET + w/4,OFFSET + h/2, 130,50, 0, -180);
		*/	
	}
	//picks a random word from specified file
	private String getRandomWord(){
		
	try{
			//creates new file 
		File theFile=new File(WORD_LIST);
		
		//adds input stream to theFile
		Scanner inputStream=new Scanner(theFile);
		
		
		int counter=0;
		//reads the number at the top of the file indicating how many words are in the file
		int n=inputStream.nextInt();
		
		//creates new random number generator that picks a number between 0 and n+1
		Random randomGenerator=new Random();
		int randomNumber=randomGenerator.nextInt(n+1);
	
		//cycles through the file and assigns the next word to String word until it reaches the specified number
		do{
		
			word=inputStream.next();
			counter++;
		}
		while(counter<randomNumber);
		
	}
		catch(FileNotFoundException fnfe){
		System.out.println("FileNotFoundException caught");
		}
		
		word=word.toLowerCase();
		
		return word;
	}
	
	//adds previous guess to list of guesses in the pastPad
	private void updatePast(){
		String theGuess=guessPad.getText();
		String previous=pastPad.getText();
		pastPad.setText(previous+theGuess);
		
	}
	
	//clears guessPad when update is pressed
	private void resetGuess(){
		guessPad.setText("");
		
	}
	
	//reports results of game if it is over
	private void updateStatus(){
		
		if(errors>=7){
			gameOver=true;
		}
		if(gameOver){
			if(errors<7){
				
				resultPad.setText("You Win");
				
				
			}
			else{
		
				resultPad.setText("You Lose");
				window.remove(updateButton);
				
			}
		}
	}
	
	//draws facial features depending on how many errors there are
	private void updateFace(){
		switch(errors){
		case 0: 
			break;
		case 1:drawContour();
			break;
		case 2:drawLeftEyebrow();
			break;
		case 3:drawRightEyebrow();
			break;
		case 4:drawLeftEye();
			break;
		case 5:drawRightEye();
			break;
		case 6:drawNose();
			break;
		case 7: drawMouth();
			break;
		}
	}
	
	//activates when update button is pushed
	public void actionPerformed(ActionEvent event) {
		// TODO Auto-generated method stub
		
		//gets the guess and converts to lowercase
		String theGuess=guessPad.getText();
		theGuess=theGuess.toLowerCase();
		
		
		if(event.getActionCommand().equals("Update")){
			//if the guess is valid then game is updated
			if(isValid(theGuess)){
				//converts string from text field to a char
				guess=theGuess.charAt(0);
				
			updatePast();
			updateAnswer();
			resetGuess();
			updateFace();
			updateStatus();
			
			}
			
		}
		
	}
	
	
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
			Smiley game=new Smiley();
			
			
	}

	

	
}
